home *** CD-ROM | disk | FTP | other *** search
Text File | 1990-08-23 | 24.1 KB | 545 lines | [TEXT/pdos] |
- Apple II
- Technical Notes
- _____________________________________________________________________________
- Developer Technical Support
-
- Apple IIgs
- #18: Do-It-Yourself SCC Access
-
- Revised by: Jim Luther July 1990
- Written by: Jim Luther, Mike Askins, Matt Deatherage & Jim Mensch June 1987
-
- This Technical Note describes how to install and remove a interrupt handler
- routine for the Z8530 Serial Communications Controller (SCC) on the Apple IIgs
- without breaking other parts of the system. This Note includes many
- suggestions that, if unheeded, could come back to haunt you in the form of bug
- fixes to your program.
- Changes since March 1990: Added a method for finding which serial port
- AppleTalk is using under GS/OS.
- _____________________________________________________________________________
-
- Free Serial Routines Inside
-
- The Z8530 SCC has 2 serial channels, supports several synchronous and
- asynchronous data communications protocols, and has 9 read registers and 16
- write registers per channel. (Compare this to the 5 registers of the 6551
- Asynchronous Communications Interface Adapter.) To program the SCC correctly,
- you must understand five things: the SCC, the Apple IIgs hardware environment
- in which the SCC lives, the Apple IIgs interrupt handler firmware, the
- interrupt support provided by the operating system, and the data communication
- protocol you want to use. If you don't understand all of these components,
- stick to the serial firmware.
-
- The Apple IIgs serial firmware is a robust environment for almost every
- asynchronous serial programming application. If you want to handle all SCC
- operations and SCC interrupts on the IIgs without using the serial firmware,
- then you must really know the firmware won't do the job for you or you
- wouldn't be going to a lot of trouble to recreate the services the firmware
- routines already provide.
-
-
- Don't Eat Your Serial with Your Mouth Open
-
- Your mother has rules and so does Apple. On many systems, your application
- may be sharing the SCC chip with System Software such as AppleTalk or the
- serial firmware. If you want to access the SCC chip directly without breaking
- the system (or the system breaking you), then follow these simple rules.
-
- Rule #1: Before using a serial port, make sure AppleTalk is not already
- using it.
-
- If AppleTalk is active, it uses one of the serial ports. The user selects
- which serial port AppleTalk uses with the Control Panel. Before using one of
- the serial ports, you should always check to make sure AppleTalk is not using
- that port. If AppleTalk is using the serial port your application wants to
- use, tough luck; tell the user about it, but don't even think about using that
- port.
-
- Under ProDOS 8, use the method shown in the following sample code to determine
- if AppleTalk is using a serial port:
-
- ;
- ; This routine checks to see which serial port, if any, AppleTalk is using.
- ; The routine sets a flag byte, ApTalkPort, and the accumulator to indicate
- ; which port (if any) AppleTalk is using.
- ; $00 = AppleTalk is not using a serial port
- ; $01 = AppleTalk is using serial port 1 (printer port)
- ; $02 = AppleTalk is using serial port 2 (modem port)
- ; Note: This method should be used under ProDOS 8 only. Under GS/OS, use the
- ; .AppleTalk driver's GetPort DStatus subcall.
- ;
- ; Enter routine in emulation mode
- ;
- longa off
- longi off
- mcopy 2/AInclude/M16.MiscTool
-
- WhichPort start
-
- IDROUTINE equ $FE1F returns system ID information
-
- stz ApTalkPort default to not AppleTalk
-
- jsr IDROUTINE call to the system ID routine
- cpy #$03
- bcs NewIIGS
-
- OldIIGS anop this is a pre-ROM 03 IIGS
- clc to native mode
- xce
- rep #$30 16 bit m and x
- longa on
- longi on
-
- pea $0000 space for result
- pea $0021 Slot 1 setting
- _ReadBParam read battery RAM parameter
- ; (2 byte result left on stack)
-
- pea $0000 space for result
- pea $0027 Slot 7 setting
- _ReadBParam read battery RAM parameter
- pla get slot 7 setting (2 bytes)
-
- sec emulation mode
- xce
- longa off
- longi off
-
- beq FindYourCard AppleTalk is active
- pla remove slot 1 setting LSB (1 byte)
- bra OldExit
-
- FindYourCard inc ApTalkPort default to port 1
- pla is slot 1 "your card"? (1 byte)
- beq ItsPort2 no, must be port 2
- bra OldExit
-
- ItsPort2 inc ApTalkPort port 2 is AppleTalk
-
- OldExit pla remove slot 1 setting MSB (1 byte)
- lda ApTalkPort
- rts return to caller
-
- NewIIGS anop ROM 03 or greater IIGS
- clc to native mode
- xce
- rep #$30 16 bit m and x
- longa on
- longi on
-
- pea $0000 space for result
- pea $000C port 2 type
- _ReadBParam read battery RAM parameter
- ; (2 byte result left on stack)
-
- pea $0000 space for result
- pea $0000 port 1 type
- _ReadBParam read battery RAM parameter
- pla get port 1 setting (2 bytes)
-
- sec emulation mode
- xce
- longa off
- longi off
-
- cmp #$02 is port 1 AppleTalk?
- bne TryPort2 no
- inc ApTalkPort yes
- pla then remove port 2 setting LSB (1 byte)
- bra NewExit and exit
-
- TryPort2 pla get port 2 setting LSB (1 byte)
- cmp #$02 is port 2 AppleTalk?
- bne NewExit no
- lda #$02 yes
- sta ApTalkPort
-
- NewExit pla remove port 2 setting MSB (1 byte)
- lda ApTalkPort
- rts return to caller
-
- ApTalkPort entry
- ds 1 will be 0, 1, or 2
- end
-
- Under GS/OS, use the method shown in the following sample code to determine if
- AppleTalk is using a serial port:
-
- ;
- ; This routine checks to see which serial port, if any, AppleTalk is using.
- ; The routine sets a flag byte, ApTalkPort, and the accumulator to indicate
- ; which port (if any) AppleTalk is using.
- ; $0000 = AppleTalk is not using a serial port
- ; $0001 = AppleTalk is using serial port 1 (printer port)
- ; $0002 = AppleTalk is using serial port 2 (modem port)
- ; Note: This method should be used under GS/OS only.
- ;
- ; Enter routine in native 16 bit mode
- ;
- longa on
- longi on
- mcopy 2/AInclude/M16.GSOS
-
- CheckPort Start
-
- GetPort equ $8001 The .AppleTalk DStatus subcall to get
- ; the port number AppleTalk is currently
- ; using.
-
- phb save data bank
- phk data bank = code bank
- plb
-
- lda #$0001 start with device #1
- sta DIdevNum
-
- FindATDriver anop
- _DInfoGS DInfoParms ;call Dinfo
- bcs DIError stop searching if error
- lda DIdeviceIDNum
- cmp #$001D is it the AppleTalk main driver?
- beq ATDriverFound yes
- inc DIdevNum check the
- bra FindATDriver next device number
-
- ATDriverFound anop
- lda DIdevNum store device number
- sta DSdevNum in the DStatus parm list
- _DStatusGS DStatusParms ;call DStatus
- lda portNum get the port number
- sta ApTalkPort
- bra Exit
-
- DIError anop
- ; cmp #$0011 invalid device number, so the
- ; beq NotFound AppleTalk main driver wasn't found
- ;
- ; Add your code to handle any other errors from DInfo here, because the
- ; end of the device list was not found.
-
- NotFound stz ApTalkPort neither port is in use
- bra Exit
-
- Exit anop
- lda ApTalkPort
- plb restore data bank
- rtl return to caller
-
- ApTalkPort entry
- ds 2 will be 0, 1, or 2
-
- DInfoParms anop
- dc i2'8' pCount = 8 parameters
- DIdevNum dc i2'1' devNum
- dc a4'NameBuffer' devName
- ds 2 characteristics
- ds 4 totalBlocks
- ds 2 slotNum
- ds 2 unitNum
- ds 2 version
- DIdeviceIDNum ds 2 deviceIDNum
-
- NameBuffer anop
- dc i2'31' Class 1 input string. Max Length=31
- ds 33
-
- DStatusParms anop
- dc i2'5' pCount = 5 parameters
- DSdevNum ds 2 devNum
- dc i2'GetPort' statusCode = GetPort
- dc a4'GetPortSList' statusList = GetPortSList
- dc i4'2' requestCount = 2
- ds 4 transferCount
-
- GetPortSList anop the GetPort subcall's statusList
- portNum ds 2 $0001 = AppleTalk is using port 1 (printer port)
- ; $0002 = AppleTalk is using port 2
- (modem port)
- dc i2'0'
-
- end
-
- Rule #2: Don't use the SCC Interrupt Handler Vector.
-
- Contrary to what you may have read in a previous version of this Note, you
- cannot reliably attach your SCC interrupt handler to the SCC Interrupt Handler
- Vector (vector reference number $0009). The Apple IIgs serial firmware owns
- the SCC Interrupt Handler Vector (or at least it thinks it does). Anytime the
- serial firmware is used, there is a chance that the serial firmware can grab
- the SCC Interrupt Handler Vector for its use. CDAs and NDAs that print, the
- Print Manager tool set, the Text tool set, and the generated GS/OS character
- drivers associated with the serial ports are examples of code that can and do
- use the serial firmware.
-
- The only safe place to connect into the interrupt chain is through the
- operating system. The ProDOS 8 and GS/OS ProDOS 16 call, ALLOC_INTERRUPT is
- the correct place to attach your interrupt handler. The GS/OS BindInt call
- cannot be used to attach your interrupt handler to the SCC Interrupt Handler
- Vector (VRN $0009) for the same reason that you cannot use the SCC Interrupt
- Handler Vector directly.
-
- Rule #3: Be very, very careful with SCC Write Register 9 (WR9).
-
- The Z8530 SCC has four registers which are shared by both channels (ports).
- Of those four, only two are commonly used in the Apple IIgs, RR3 and WR9.
- RR3, which only exists in channel A, lets you check the interrupt pending bits
- for both SCC channels. WR9 is the Master Interrupt Control register for both
- SCC channels and contains the Reset command bits.
-
- You must never reset the channel AppleTalk is using (resetting the channel
- AppleTalk is using kills AppleTalk). This means you should never perform a
- Force Hardware Reset command (11xxxxxx to WR9) even though the Z8530 Serial
- Communications Controller Technical Manual tells you to in the SCC
- initialization procedure. A hardware reset is performed at system startup, so
- you shouldn't need to perform a channel reset, even to the channel you are
- using.
-
- The interrupt control bits (bits D5 - D0) in WR9 should not be modified (an
- exception is when you are installing your own SCC interrupt handler).
- AppleTalk expects the interrupt control bits to always be 001010. If you find
- the need to perform a channel reset on your channel, remember that the
- interrupt control bits are programmed at the same time as a channel reset.
-
-
- Hints for the Serial Adventure
-
- Next are a few hints for those who would like to explore the world of knocking
- on the registers of the Z8530 SCC.
-
- Hint #1: Synchronize your code with the SCC logic.
-
- Before writing to the SCC chip for the first time, you should make an attempt
- to ensure your code is synchronized with the SCC's logic. This needs to be
- done only once when you are initializing the SCC. This can be accomplished
- with a single read of SCC Read Register 0 (RR0). For example, if you're using
- serial port 2 (the modem port), the following code reads RR0 of SCC channel B:
-
- longa off must be using 8-bit accumulator
- lda $C038 read RR0 of SCC Channel B
-
- Hint #2: Watch out for interrupts from the other SCC channel.
-
- Except for RR0, WR0, and the two SCC data registers, all SCC registers are
- accessed in a two-step process. First, the register number you want to select
- is written to WR0. After the register number is set, the next read from or
- write to the command register accesses the register selected in the first
- step. Because several of the SCC registers are shared between the two SCC
- channels and because code accessing them may not always be yours (i.e.,
- AppleTalk), interrupts should be disabled during the two steps. The following
- code shows two quick subroutines to access the SCC's Read and Write registers
- while preventing interrupts between the register number set and the register
- read or write steps:
-
- longa off must be using 8-bit accumulator
- longi off and index registers
- ;
- ; Write to a SCC command register - channel A or B.
- ; Input: A = value to store
- ; X = SCC register number ($0-$F)
- ; Y = $01 channel A
- ; $00 channel B
- ;
- WriteSCC php save the current interrupt status
- sei disable interrupts
- pha save value to write
- txa get SCC register number from X
- sta $C038,y set the register number
- pla restore value to write
- sta $C038,y write the value
- plp restore the interrupt status
- rts
-
- ;
- ; Read from a SCC command register - channel A or B.
- ; Input: A = SCC register number ($0-$F)
- ; Y = $01 channel A
- ; $00 channel B
- ; Output: A = register value
- ;
- ReadSCC php save the current interrupt status
- sei disable interrupts
- sta $C038,y set the SCC register number
- lda $C038,y get the value from the SCC register
- xba look ahead 2 lines...
- plp restore the interrupt status
- xba set N and Z flags for exit
- rts
-
- Just to be complete, here's how RR0, WR0, the receive buffer, and the transmit
- buffer SCC registers are accessed on the Apple IIgs:
-
- longa off must be using 8-bit accumulator
- longi off and index registers
- ;
- ; Read RR0 - channel A or B
- ; Input: Y = $01 channel A
- ; $00 channel B
- ; Output: A = RR0 register value
- ;
- ReadRR0 lda $C038,y get the value from RR0
- rts
- ;
- ; Write WR0 - channel A or B
- ; Input: A = value to store at WR0
- ; Y = $01 channel A
- ; $00 channel B
- ;
- WriteWR0 sta $C038,y write the value to WR0
- rts
- ;
- ; Read from SCC receive buffer - channel A or B
- ; Input: Y = $01 channel A
- ; $00 channel B
- ; Output: A = value of data received
- ;
- ReadData lda $C03A,y get the value from SCC data register
- rts
- ;
- ; Write to SCC transmit buffer - channel A or B
- ; Input: A = value of data to transmit
- ; Y = $01 channel A
- ; $00 channel B
- ;
- WriteData sta $C03A,y write the value to SCC data register
- rts
-
- Hint #3: All SCC channels are not created equal.
-
- In the IIgs, the SCC's receive and transmit clocks for both channels are
- driven by a single crystal oscillator circuit. This is accomplished by
- connecting a 3.6864 MHz crystal between the /RTxC and /SYNC pins of channel A.
- Channel B's /RTxC pin is connected to Channel A's /SYNC pin to drive
- channel B's clocks from channel A's oscillator circuit.
-
- Because of this single circuit, Write Register 11 (WR11) bit 7 must be set to
- 1 for SCC channel A and must be set to 0 for SCC channel B.
-
- Hint #4: RR3 is available only in SCC channel A.
-
- When your interrupt handler is checking to see if the interrupt condition was
- caused by your SCC channel, remember to always look at RR3 in SCC channel A.
- RR3 in channel A contains the interrupt pending bits for both SCC channels.
- RR3 in channel B always returns all zeros, which doesn't tell you a lot about
- what's happening.
-
-
- Don't be a Serial Killer
-
- How to Install and Remove your SCC Interrupt Handler
-
- If you're going to handle serial I/O and don't want your application to have
- to poll the SCC chip all the time to see if something has happened, you
- probably want to install an interrupt handling routine that is called every
- time a SCC chip condition you want to know about occurs. This section of the
- Note shows how to install and remove your own SCC interrupt handler.
-
- The steps for installing your SCC interrupt handler are:
-
- 1. Ensure the serial firmware's Input and Output buffering is
- disabled. The state of I/O buffering can be checked by looking at
- bit 14 of the ModeBitImage parameter returned by the GetModeBits
- extended interface call. I/O buffering can be disabled with the
- firmware's BD control command.
- 2. Disable the SCC Master Interrupt Enable (WR9, bit 3) briefly while
- performing the next six steps. The value you should write to WR9
- is 00000010.
- 3. Get the address of the system interrupt flag byte, SerFlag. The
- ROM version determines the method of finding the address of
- SerFlag. In ROM version 01 and later, you can get the address
- with a call to the Miscellaneous Tools GetAddr using a reference
- number of $000E. With ROM version 00 (the original IIgs ROM), the
- address of SerFlag is $E10104. Refer to the Apple II
- Miscellaneous Technical Note #7, Apple II Family Identification
- for information on identifying Apple IIgs ROM versions.
- 4. Once you have the correct address of SerFlag, preserve the byte's
- current value, then turn on the bits in the byte which reflect the
- port from which you are handling interrupts. The bits for the
- different ports are as follows (note the relationship of the bits
- of RR3 to SerFlag):
-
- Port 1: ORA #%00111000
- Port 2: ORA #%00000111
-
-
- 5. Initialize the SCC modes. The Z8530 Serial Communications
- Controller Technical Manual shows the order the SCC registers
- must be programmed. However, you must stray from the manual
- slightly due to the hardware implementation of the SCC in the
- IIgs. A typical initialization sequence to set the SCC up for
- asynchronous serial communications through channel B (the modem
- port) would look similar to the following:
-
- SCC Register Value Comment
- RR0 - ensure synchronization with SCC
- WR4 01000100 x16 clock, 1 stop, no parity
- WR3 11000000 8 bit receive data, auto enables off,
- receiver disabled
- WR5 01100010 DTR is active, 8 bit transmit data, no break,
- transmit disabled, RTS is inactive
- WR11 01010000 no Xtal on channel B, receive and
- transmit clock = baud rate generator output
- WR12 01011110 low byte of baud rate generator
- time constant = $5E - 1200 baud
- WR13 00000000 high byte of baud rate generator
- time constant = $00 - 1200 baud
- WR14 00000000 no local loopback or auto echo, /DTR follows
- inverted DTR bit in WR5, use /RTxC for
- baud rate generator clock,
- disable baud rate generator
- WR14 00000001 enable the baud rate generator
- WR3 11000001 receiver enabled
- WR5 01101010 transmit enabled
- WR15 00000000 no interrupts on this channel for now...
-
- 6. Tell the SCC which external and status conditions can cause an
- interrupt by setting the appropriate bits in WR15. This step is
- not needed unless you are setting bit 0 of WR1 (External/Status
- Master Interrupt Enable) in the next step.
- 7. Enable the interrupts modes you want by setting the appropriate
- bits in WR1 (00010011 for all SCC interrupt conditions).
- 8. Use ALLOC_INTERRUPT to add your interrupt handler to the operating
- system's interrupt vector table. The interrupt identification
- number returned by ALLOC_INTERRUPT is needed when you remove your
- interrupt handler.
- 9. Reenable the SCC Master Interrupt flag (WR9, bit 3). The value
- you should write to WR9 is 00001010.
-
- The interrupt handling routine must conform to the rules listed in the
- ProDOS 8 Technical Reference Manual and GS/OS Reference, Volume 2.
-
- When you get ready to shut down your application, you need to remove your
- interrupt handler. The steps for removing the SCC interrupt handler you
- installed are as follows:
-
- 1. Disable the SCC Master Interrupt Enable (WR9, bit 3) briefly while
- performing the next six steps. The value you should write to WR9
- is 00000010.
- 2. Disable all interrupts modes for your port by writing a $00 to WR1.
- 3. Remove any character that might be left in the receive data
- register by reading it once.
- 4. Clear any pending transmit overrun and external and status
- interrupts by writing 11010000 to WR0.
- 5. Clear any pending transmit interrupt by writing 00101000 to WR0.
- 6. Use DEALLOC_INTERRUPT to remove your interrupt handler from the
- operating system's interrupt vector table.
- 7. Restore SerFlag to its original value.
- 8. Reenable the SCC Master Interrupt flag (WR9, bit 3). The value
- you should write to WR9 is 00001010.
-
-
- Further Reference
- _____________________________________________________________________________
- o Apple IIgs Toolbox Reference Manual, Volume 1
- o Apple IIgs Firmware Reference Manual
- o Apple IIgs Hardware Reference Manual, Second Edition
- o GS/OS Reference, Volumes 1 and 2
- o ProDOS 8 Technical Reference Manual
- o Apple II Miscellaneous Technical Note #7, Apple II Family Identification
- o GS/OS Technical Note #9, Interrupt Handling Anomalies
- o Z8530 Serial Communications Controller Technical Manual
- (Zilog Corporation)
- o Z85C30 Serial Communications Controller Technical Manual
- (Advanced Micro Devices, Inc.)
-
-